/*
 * FileName: ManyNodeTree.java
 * Author:   zzw
 * Date:     2018年05月25日
 * Description:
 */
package com.chezhibao.trace.vo;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 〈〉<br>
 * 〈〉
 *
 * @author zzw
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本]（可选）
 */
public class ManyNodeTree {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static  Map<Integer,String> rpcTypeNames = new HashMap<>();

    /*TYPE_TRACE = 0;
    TYPE_CSF_CLIENT = 1;
    TYPE_CSF_SERVER = 2;
    TYPE_MYSQL = 3;
    TYPE_REDIS = 4;
    TYPE_HTTP = 5;
    TYPE_MQ = 6;
    TYPE_INDEX = 9;*/
    static {
        rpcTypeNames.put(0,"Trace");
        rpcTypeNames.put(1,"CSF_CLIENT");
        rpcTypeNames.put(2,"CSF_SERVER");
        rpcTypeNames.put(3,"MYSQL");
        rpcTypeNames.put(4,"REDIS");
        rpcTypeNames.put(5,"HTTP");
        rpcTypeNames.put(6,"MQ");
        rpcTypeNames.put(9,"");
    }

    /**
     * 树根
     */
    private ManyTreeNode root;

    /**
     * 构造函数
     */
    public ManyNodeTree(String nodeId) {
        root = new ManyTreeNode(new ManyTreeNode.TreeNode(nodeId));
    }

    public ManyNodeTree(Msg vo) {
        root = new ManyTreeNode(new ManyTreeNode.TreeNode(vo.getRpcId(), null, vo));
    }

    public ManyNodeTree createTree3(List<Message> list) {
        ManyTreeNode.TreeNode treeNode = null;
        if (list == null || list.size() < 0) {
            return null;
        }
        //将所有节点添加到多叉树中
        for (Message message : list) {
            String nodeId = this.getRoot().getData().getNodeId();
            Integer rpcType = this.getRoot().getData().getMessage().getRpcType();
            if (message.getRpcId().contains(nodeId)) {
                String[] split = message.getQualifer().split("\\-");
                //MQ另行处理
                if (rpcType == 6 && split[0].split("\\.").length - nodeId.split("\\.").length == 2){
                    handleFirstNode(message,list,treeNode,nodeId,split);
                }
                else if(split[0].split("\\.").length - nodeId.split("\\.").length == 1) {
                    handleFirstNode(message,list,treeNode,nodeId,split);
                }
                else {
                    addChild3(this.getRoot(), message,list);
                }
            }
            else {
                addChild3(this.getRoot(), message,list);
            }
        }
        return this;
    }

    public void addChild3(ManyTreeNode manyTreeNode, Message message,List<Message> list) {

        ManyTreeNode.TreeNode treeNode = null;

        for (ManyTreeNode item : manyTreeNode.getChildList()) {
            List<ManyTreeNode> childList = item.getChildList();
            String nodeId = item.getData().getNodeId();
            String rpcId = message.getRpcId();
            String[] split = rpcId.split("\\.");
            String[] split4 = nodeId.split("\\.");
            Msg message2 = item.getData().getMessage();

            //http特别处理
            if(message.getRpcType() == 0){
                for (ManyTreeNode item2 : manyTreeNode.getChildList()) {
                    Msg msg = item2.getData().getMessage();
                    if(!msg.getQualifer().equals(message2.getQualifer()) && msg.getRpcId().equals(message2.getRpcId())){
                        msg.setAppname(message2.getAppname());
                        return;
                    }
                }
            }
            else if (message.getRpcType() == 6 && "MQRecv".equals(message.getServiceName())){
                StringBuffer id = new StringBuffer();
                for (int i = 0;i< split.length - 1;i ++){
                    if (i == split.length - 2){
                        id.append(split[i]);
                    }
                    else {
                        id.append(split[i]).append(".");
                    }
                }
                if (id != null && id.toString().contains(nodeId) && split.length - split4.length == 2){
                    addData(message,rpcId,nodeId,item,treeNode,childList);
                }
            }
            if (rpcId.contains(nodeId) && split.length - split4.length == 1) {
                boolean flag = false;
                for (int i = 0; i < split4.length; i++) {
                    if (!split4[i].equals(split[i])) {
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    //已经存了rpctye = 0,只需要修改数据
                    if(message.getRpcType() == 5){
                        for (ManyTreeNode item2 : item.getChildList()) {
                            Msg msg = item2.getData().getMessage();
                            if(!msg.getQualifer().equals(message.getQualifer()) && msg.getRpcId().equals(message.getRpcId())){
                                handleMsg(message,msg);
                                return;
                            }
                        }
                        //没有记录，就添加
                        addData(message,rpcId,nodeId,item,treeNode,childList);
                    }
                    else if (message.getRpcType() != 1 && message.getRpcType() != 2) {
                        addData(message,rpcId,nodeId,item,treeNode,childList);
                    }
                    else {
                        String[] split1 = message2.getRpcId().split("\\.");
                        if (split.length - split1.length == 1 && split[split.length - 2].equals(split1[split1.length - 1])) {
                            Iterator<Message> iterator = list.iterator();
                            Message message1 = null;

                            String[] split3 = message.getQualifer().split("\\-");
                            while (iterator.hasNext()) {
                                Message next = iterator.next();
                                String[] split2 = next.getQualifer().split("\\-");
                                try {
                                    if (split3[0].equals(split2[0]) && !split3[1].equals(split2[1])) {
                                        message1 = next;
                                        break;
                                    }
                                } catch (Exception e) {

                                }
                            }

                            if (childList == null || childList.size() == 0) {
                                treeNode = handAndConvert(message, message1, nodeId);
                                item.getChildList().add(new ManyTreeNode(treeNode));
                            }
                            else {
                                boolean flag2 = false;
                                for (ManyTreeNode node : item.getChildList()) {
                                    if (node.getData().getNodeId().contains(rpcId)) {
                                        flag2 = true;
                                    }
                                }
                                if (!flag2) {
                                    treeNode = handAndConvert(message, message1, nodeId);
                                    item.getChildList().add(new ManyTreeNode(treeNode));
                                }
                            }
                        } else {
                            addChild3(item, message, list);
                        }
                    }
                } else {
                    if (item.getChildList() != null && item.getChildList().size() > 0) {
                        addChild3(item, message, list);
                    }
                }
            }
            else {
                addChild3(item, message, list);
            }
        }
    }

    /**
     * 遍历多叉树
     *
     * @param manyTreeNode 多叉树节点
     * @return
     */
    public void iteratorTree(ManyTreeNode manyTreeNode,Long startTime) {

        if (manyTreeNode != null) {

            List<ManyTreeNode> childList = manyTreeNode.getChildList();
            Collections.sort(childList, new Comparator<ManyTreeNode>() {
                @Override
                public int compare(ManyTreeNode o1, ManyTreeNode o2) {
                    String[] split = o1.getData().getNodeId().split("\\.");
                    String[] split2 = o2.getData().getNodeId().split("\\.");
                    if ((Integer.parseInt(split[split.length - 1]) - Integer.parseInt(split2[split2.length - 1])) < 0) {
                        return -1;
                    }
                    return 1;
                }
            });

            for (int i = 0; i < childList.size(); i ++){
                ManyTreeNode index = childList.get(i);
                Msg message = index.getData().getMessage();
                String userData = message.getUserData();
                if(userData!= null && !"".equals(userData) && userData.contains("@@")){
                    String s = userData.replaceAll("\u0014", "=").replaceAll("\u0012", "&");
                    if("&".equals(s.substring(s.length() - 1))){
                        s = s.substring(0,s.length() - 1);
                        message.setUserData(s.substring(1));
                    }
                    else {
                        message.setUserData(s.substring(1));
                    }
                }
                else {
                    if (message.getUserData() == null || "null".equals(message.getUserData())){
                        message.setUserData("");
                    }
                }
                //logger.info(index.getData().getNodeId() + "---" + index.getData().getMessage().getUserData());
                String serverData = message.getServerData();
                if(serverData!= null && !"".equals(serverData)){
                    String s = serverData.replaceAll("\u0014", "=").replaceAll("\u0012", "&");
                    if("&".equals(s.substring(s.length() - 1))){
                        s = s.substring(0,s.length() - 1);
                        message.setServerData(s.substring(1));
                    }
                    else {
                        message.setServerData(s.substring(1));
                    }
                }
                else {
                    if (message.getServerData() == null || "null".equals(message.getServerData())){
                        message.setServerData("");
                    }
                }

                String resultCode = message.getResultCode();
                if("00".equals(resultCode)){
                    message.setResultCode("调用成功");
                }
                else if("200".equals(resultCode)){
                    message.setResultCode("调用成功");
                }
                else if("01".equals(resultCode)){
                    message.setResultCode("返回业务异常");
                }
                else if("02".equals(resultCode)){
                    message.setResultCode("调用过程中出现异常");
                }
                else if("03".equals(resultCode)){
                    message.setResultCode("调用超时");
                }

                //String span = message.getSpan();

                if (message.getRemoteIp() == null){
                    message.setRemoteIp("");
                }
                if (message.getRequestSize() == null || "null".equals(message.getRequestSize())){
                    message.setRequestSize("");
                }
                if (message.getResponseSize() == null || "null".equals(message.getResponseSize())){
                    message.setResponseSize("");
                }
                if (message.getMethodName() == null){
                    message.setMethodName("");
                }

                long start = message.getStartTime() - startTime;
                String[] spans = {start + "", message.getSpan()};
                message.setSpans(spans);

                if (index.getChildList() != null && index.getChildList().size() > 0) {
                    iteratorTree(index,startTime);
                }
            }
        }
    }

    public ManyTreeNode getRoot() {
        return root;
    }

    public void setRoot(ManyTreeNode root) {
        this.root = root;
    }

    public ManyTreeNode.TreeNode handAndConvert(Message message1, Message message2,String parentId) {
        ManyTreeNode.TreeNode treeNode = null;
        Msg msg = new Msg();
        msg.setAppname(message1.getAppname());
        msg.setMethodName(message1.getMethodName());
        msg.setRemoteIp(message1.getRemoteIp());
        msg.setResultCode(message1.getResultCode());
        msg.setRpcId(message1.getRpcId());
        msg.setServiceName(message1.getServiceName());
        msg.setStartTime(message1.getStartTime());
        msg.setTraceName(message1.getTraceName());

        String userData = message1.getUserData();
        if(userData != null && !"".equals(userData)){
            if(userData.contains("\u0014")) {
                String s = userData.replaceAll("\u0014", "=").replaceAll("\u0012", "&");
                if ("&".equals(s.substring(s.length() - 1))) {
                    s = s.substring(0, s.length() - 1);
                    msg.setUserData(s.substring(1));
                } else {
                    msg.setUserData(s.substring(1));
                }
            }
            else {
                msg.setUserData(userData);
            }
        }
        else {
            msg.setUserData("");
        }

        String[] split = message1.getSpan().split("\\,");
        if(message2 != null){
            msg.setRequestSize(message2.getRequestSize() + "");
            msg.setSpanServer(message2.getSpan());
            msg.setAppname(message2.getAppname());
            msg.setServerData(message2.getServerData());
        }
        else {
            msg.setRequestSize(message1.getRequestSize() + "");
        }
        if(split.length == 2){
            msg.setSpan(Integer.parseInt(split[1].substring(0, split[1].length() - 1).trim()) + "");
        }
        else{
            msg.setSpan(Integer.parseInt(split[0]) + "");
        }
        msg.setResponseSize(message1.getResponseSize() + "");
        if(message1.getSql() != null){
            msg.setSql(message1.getSql());
        }
        if(message1.getRpcType() != null){
            msg.setRpcType(message1.getRpcType());
            msg.setRpcTypeName(rpcTypeNames.get(msg.getRpcType()));
        }
        msg.setQualifer(message1.getQualifer().split("-")[0]);
        treeNode = new ManyTreeNode.TreeNode(message1.getRpcId(), parentId, msg);
        return treeNode;
    }

    protected ManyTreeNode.TreeNode handCommon(Message message,String parentId) {
        ManyTreeNode.TreeNode treeNode = null;
        Msg msg = new Msg();
        msg.setAppname(message.getAppname());
        msg.setMethodName(message.getMethodName());
        msg.setRemoteIp(message.getRemoteIp());
        msg.setResultCode(message.getResultCode());
        msg.setRpcId(message.getRpcId());
        msg.setServiceName(message.getServiceName());
        msg.setStartTime(message.getStartTime());
        msg.setTraceName(message.getTraceName());

        String userData = message.getUserData();
        if(userData != null && !"".equals(userData)){
            if(userData.contains("\u0014")) {
                String s = userData.replaceAll("\u0014", "=").replaceAll("\u0012", "&");
                if ("&".equals(s.substring(s.length() - 1))) {
                    s = s.substring(0, s.length() - 1);
                    msg.setUserData(s.substring(1));
                } else {
                    msg.setUserData(s.substring(1));
                }
            }
            else {
                msg.setUserData(userData);
            }
        }
        else {
            msg.setUserData("");
        }

        String[] split = message.getSpan().split("\\,");

        msg.setRequestSize(message.getRequestSize() + "");
        msg.setSpanServer(message.getSpan());
        msg.setAppname(message.getAppname());
        msg.setServerData(message.getServerData());

        msg.setRequestSize(message.getRequestSize() + "");

        if(split.length == 2){
            msg.setSpan(Integer.parseInt(split[1].substring(0, split[1].length() - 1).trim()) + "");
        }
        else{
            msg.setSpan(Integer.parseInt(split[0]) + "");
        }
        msg.setResponseSize(message.getResponseSize() + "");
        if(message.getSql() != null){
            msg.setSql(message.getSql());
        }
        if(message.getRpcType() != null){
            msg.setRpcType(message.getRpcType());
            msg.setRpcTypeName(rpcTypeNames.get(msg.getRpcType()));
        }
        msg.setQualifer(message.getQualifer());
        treeNode = new ManyTreeNode.TreeNode(message.getRpcId(), parentId, msg);
        return treeNode;
    }

    protected void addData(Message message,String rpcId,String nodeId,ManyTreeNode item,ManyTreeNode.TreeNode treeNode,List<ManyTreeNode> childList){
        treeNode = handCommon(message, nodeId);
        if (childList == null || childList.size() == 0) {
            childList.add(new ManyTreeNode(treeNode));
        }
        else {
            boolean flag2 = false;
            for (ManyTreeNode node : item.getChildList()) {
                if (node.getData().getNodeId().contains(rpcId)) {
                    flag2 = true;
                    break;
                }
            }
            if (!flag2) {
                childList.add(new ManyTreeNode(treeNode));
            }
        }
    }

    protected void handleFirstNode(Message message,List<Message> list,ManyTreeNode.TreeNode treeNode,String nodeId,String[] split) {
        List<ManyTreeNode> childList = this.getRoot().getChildList();
        Iterator<Message> iterator = list.iterator();
        if (message.getRpcType() != 1 && message.getRpcType() != 2) {
            treeNode = handCommon(message, nodeId);
        }
        else {
            while (iterator.hasNext()) {
                Message next = iterator.next();
                String[] split2 = next.getQualifer().split("\\-");
                if (split[0].equals(split2[0]) && !split[1].equals(split2[1])) {
                    int i = Integer.parseInt(split[1]) - Integer.parseInt(split2[1]);
                    if (i < 0) {
                        treeNode = handAndConvert(message, next, nodeId);
                    } else if (i > 0) {
                        treeNode = handAndConvert(next, message, nodeId);
                    } else {
                        continue;
                    }
                    break;
                }
            }
        }
        if(treeNode == null){
            treeNode = handAndConvert(message,null,nodeId);
        }
        if (childList == null || childList.size() == 0) {
            this.getRoot().getChildList().add(new ManyTreeNode(treeNode));
        }
        else {
            boolean flag = false;
            for (ManyTreeNode node : this.getRoot().getChildList()) {
                if (node.getData().getNodeId().contains(message.getRpcId())) {
                    flag = true;
                }
            }
            if (!flag) {
                this.getRoot().getChildList().add(new ManyTreeNode(treeNode));
            }
        }
    }

    //rpctype = 5
    protected void handleMsg(Message message,Msg msg){
        msg.setStartTime(message.getStartTime());
        String span = message.getSpan().split(",")[1];
        msg.setSpan(span.substring(1, span.length() - 1));
        msg.setTraceName(message.getTraceName());
        msg.setResultCode(message.getResultCode());
        String userData = message.getUserData();
       /*
        if(userData != null){
            if(userData != null && userData.contains("\u0014")){
                String[] split = userData.split("\u0014");
                msg.setUserData(split[split.length - 1].substring(0,split[split.length - 1].length() - 1));
            }
        }*/
        msg.setUserData(userData);
        msg.setServerData(message.getServerData());
        msg.setServiceName(message.getServiceName());
        msg.setMethodName(message.getMethodName());
        msg.setRemoteIp(message.getRemoteIp());
        msg.setRpcType(message.getRpcType());
        msg.setQualifer(message.getQualifer());
        msg.setRpcTypeName(rpcTypeNames.get(msg.getRpcType()));
    }
}
